/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.opengoofy.index12306.biz.ticketservice.service.handler.ticket.select;

import cn.hutool.core.collection.CollUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * 座位选择器
 * 公众号：马丁玩编程，回复：加群，添加马哥微信（备注：12306）获取项目资料
 */
public class SeatSelection {

    /**
     * 根据给定的座位布局和所需连续座位数，找出符合条件的座位区域
     * 
     * @param numSeats     需要的连续座位数
     * @param seatLayout   二维数组表示的座位布局，0表示空座位，1表示已被占用的座位
     * @return             如果找到符合条件的座位区域，则返回一个二维数组，包含这些座位的行和列
     *                     如果没有找到，则返回null
     */
    public static int[][] adjacent(int numSeats, int[][] seatLayout) {
        // 座位布局的行数
        int numRows = seatLayout.length;
        // 座位布局的列数
        int numCols = seatLayout[0].length;
        // 用于存储找到的符合条件的座位坐标
        List<int[]> selectedSeats = new ArrayList<>();
        
        // 遍历座位布局，寻找符合条件的连续空座位
        for (int i = 0; i < numRows; i++) {
            for (int j = 0; j < numCols; j++) {
                // 当前座位为空时，开始检查连续空座位
                if (seatLayout[i][j] == 0) {
                    // 记录当前找到的连续空座位数
                    int consecutiveSeats = 0;
                    // 从当前座位开始，向右检查连续空座位
                    for (int k = j; k < numCols; k++) {
                        if (seatLayout[i][k] == 0) {
                            consecutiveSeats++;
                            // 如果找到所需数量的连续空座位
                            if (consecutiveSeats == numSeats) {
                                // 将这些座位的坐标添加到selectedSeats列表中
                                for (int l = k - numSeats + 1; l <= k; l++) {
                                    selectedSeats.add(new int[]{i, l});
                                }
                                break;
                            }
                        } else {
                            // 遇到非空座位，重置连续空座位计数
                            consecutiveSeats = 0;
                        }
                    }
                    // 如果已经找到符合条件的座位，跳出内层循环
                    if (!selectedSeats.isEmpty()) {
                        break;
                    }
                }
            }
            // 如果已经找到符合条件的座位，跳出外层循环
            if (!selectedSeats.isEmpty()) {
                break;
            }
        }
        
        // 如果没有找到符合条件的座位，返回null
        if (CollUtil.isEmpty(selectedSeats)) {
            return null;
        }
        
        // 创建一个二维数组，用于存储实际的座位坐标（行和列都加1，以符合人类友好的坐标系）
        int[][] actualSeat = new int[numSeats][2];
        int i = 0;
        // 遍历selectedSeats列表，填充actualSeat数组
        for (int[] seat : selectedSeats) {
            int row = seat[0] + 1;
            int col = seat[1] + 1;
            actualSeat[i][0] = row;
            actualSeat[i][1] = col;
            i++;
        }
        
        // 返回找到的座位坐标
        return actualSeat;
    }

    /**
     * 根据给定的座位布局和座位数量，选择不相邻的座位
     * 
     * @param numSeats 需要选择的座位数量
     * @param seatLayout 二维数组，表示座位布局，其中0表示可选座位，其他值表示不可选
     * @return 返回一个二维数组，表示选中的座位在原布局中的位置
     */
    public static int[][] nonAdjacent(int numSeats, int[][] seatLayout) {
        // 获取座位布局的行数
        int numRows = seatLayout.length;
        // 获取座位布局的列数
        int numCols = seatLayout[0].length;
        // 创建一个列表，用于存储选中的座位的行列值
        List<int[]> selectedSeats = new ArrayList<>();
        // 遍历座位布局
        for (int i = 0; i < numRows; i++) {
            for (int j = 0; j < numCols; j++) {
                // 当前座位可选时，将其行列值添加到列表中
                if (seatLayout[i][j] == 0) {
                    selectedSeats.add(new int[]{i, j});
                    // 如果已选中的座位数量达到要求，跳出循环
                    if (selectedSeats.size() == numSeats) {
                        break;
                    }
                }
            }
            // 如果已选中的座位数量达到要求，跳出循环
            if (selectedSeats.size() == numSeats) {
                break;
            }
        }
        // 将选中的座位转换为实际座位的二维数组形式返回
        return convertToActualSeat(selectedSeats);
    }

    /**
     * 将选择的座位编号转换为实际座位坐标
     * 由于座位编号是从0开始的，而实际座位号是从1开始的，因此需要对每个座位的行和列编号进行转换
     * 
     * @param selectedSeats 选择的座位编号列表，每个元素是一个包含两个整数的数组，分别代表行和列
     * @return 实际的座位坐标数组，每个元素是一个包含两个整数的数组，分别代表实际的行坐标和列坐标
     */
    private static int[][] convertToActualSeat(List<int[]> selectedSeats) {
        // 初始化实际座位坐标数组，大小与选择的座位数量相同
        int[][] actualSeat = new int[selectedSeats.size()][2];
        for (int i = 0; i < selectedSeats.size(); i++) {
            // 获取当前选择的座位
            int[] seat = selectedSeats.get(i);
            // 将座位的行编号加1，转换为实际的行坐标
            int row = seat[0] + 1;
            // 将座位的列编号加1，转换为实际的列坐标
            int col = seat[1] + 1;
            // 将转换后的行和列坐标保存到实际座位坐标数组中
            actualSeat[i][0] = row;
            actualSeat[i][1] = col;
        }
        // 返回实际座位坐标数组
        return actualSeat;
    }

    public static void main(String[] args) {
        int[][] seatLayout = {
                {1, 1, 1, 1},
                {1, 1, 1, 0},
                {1, 1, 1, 0},
                {0, 0, 0, 0}
        };
        int[][] select = adjacent(2, seatLayout);
        System.out.println("成功预订相邻座位，座位位置为：");
        assert select != null;
        for (int[] ints : select) {
            System.out.printf("第 %d 排，第 %d 列%n", ints[0], ints[1]);
        }

        int[][] seatLayoutTwo = {
                {1, 0, 1, 1},
                {1, 1, 0, 0},
                {1, 1, 1, 0},
                {0, 0, 0, 0}
        };
        int[][] selectTwo = nonAdjacent(3, seatLayoutTwo);
        System.out.println("成功预订不相邻座位，座位位置为：");
        for (int[] ints : selectTwo) {
            System.out.printf("第 %d 排，第 %d 列%n", ints[0], ints[1]);
        }
    }
}
